﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Reflection;
using System.Text;
using System.Web;
using Microsoft.Practices.EnterpriseLibrary.Logging;

namespace OVS.Common
{
    public sealed class LogHelper
    {
        #region Member

        public enum MethodPosition
        {
            Start,
            Middle,
            End
        }

        private static readonly Boolean C_BOOL_HEADER_WRITTEN;

        private static readonly string C_STR_EVENT_CATEGORY;
        private static readonly string LogSetting = "1";

        //default message id
        private static int C_INT_MSG_ID;
        private static string C_STR_EVENT_CATEGORY_PHIDIAS = "General";

        //if the header has been written or not
        private static string C_STR_FOOTER_CATEGORY = "Footer Events";
        private static string C_STR_FOOTER_MSG = "creating footer";
        private static string C_STR_HEADER_CATEGORY = "All Events"; //"Header Events";
        private static string C_STR_HEADER_MSG = "creating header";
        private static int m_priorityError = 3;

        //PHIDIAS Event Category - General

        //Message Priority
        private static int m_priorityInfo = 1;
        private static int m_priorityWarning = 2;

        //To hold user's UTCode
        private static string UserLogUTCode = "";

        private enum Priority
        {
            INFO,
            WARNING,
            ERROR
        }

        #endregion

        #region Constructor

        /**
		* p_strCategory	    Log category
		* p_intId			Process Id			
		* */

        static LogHelper()
        {
            //we define a default category
            C_STR_EVENT_CATEGORY = "UI Events";

            if (!C_BOOL_HEADER_WRITTEN)
            {
                Logger.Write(C_STR_HEADER_MSG, C_STR_HEADER_CATEGORY, m_priorityInfo, C_INT_MSG_ID,
                             TraceEventType.Information);
                C_BOOL_HEADER_WRITTEN = true;
            }

            try
            {
                LogSetting = ConfigurationManager.AppSettings["PHIDIASLogLevel"];
            }
            catch
            {
            }
            GetUserLogUTCode();
        }

        #endregion

        #region Public Method(s)

        //Write footer message
        public static void WriteFooter()
        {
            try
            {
                Logger.Write(C_STR_FOOTER_MSG, C_STR_FOOTER_CATEGORY, m_priorityInfo, C_INT_MSG_ID,
                             TraceEventType.Information);
            }
            catch
            {
            }
        }

        //Info message
        public static void WriteInfo(string p_strMessage)
        {
            try
            {
                if (LogSetting == "0" || LogSetting == "1")
                    return;

                if (p_strMessage != "System.Collections.Generic.Dictionary`2[System.String,System.String]")
                    Logger.Write(p_strMessage, C_STR_EVENT_CATEGORY, m_priorityInfo, C_INT_MSG_ID,
                                 TraceEventType.Information);
            }
            catch
            {
            }
        }


        //Info message
        public static void WriteInfo(string p_strMessage, MethodPosition Position)
        {
            try
            {
                if (LogSetting == "0" || LogSetting == "1")
                    return;

                StackFrame fr = new StackFrame(1, true);
                StackTrace st = new StackTrace(fr);
                string strMessage = string.Empty;

                LogEntry log = new LogEntry();
                log.Categories.Add("General");
                log.Priority = m_priorityInfo;
                log.EventId = C_INT_MSG_ID;
                log.Severity = TraceEventType.Information;

                log.ExtendedProperties.Add("Method", fr.GetMethod().Name + " | ");
                log.ExtendedProperties.Add("UserLogUTCode", GetUserLogUTCode() + " | ");

                strMessage = GetCurrentContextForLogging(fr.GetFileName()) + " " + Position + " Method: " +
                             fr.GetMethod().Name + "| Info ---> ";

                log.Message = strMessage + p_strMessage;
                Logger.Write(log);
            }
            catch
            {
            }
        }

        public static void WriteInfo(object obj)
        {
            try
            {
                if (LogSetting == "0" || LogSetting == "1")
                    return;

                StackFrame fr = new StackFrame(1, true);

                LogEntry log = new LogEntry();
                log.Categories.Add("General");
                log.Priority = m_priorityInfo;
                log.EventId = C_INT_MSG_ID;
                log.Severity = TraceEventType.Information;
                log.ExtendedProperties.Add("UserLogUTCode", GetUserLogUTCode() + " | ");
                log.Message = string.Format("Entering Method: {0} Info ---> {1}", fr.GetMethod().Name, BuildLog(obj));

                Logger.Write(log);
            }
            catch
            {
            }
        }

        public static void WriteInfo(params string[] infos)
        {
            try
            {
                if (LogSetting == "0" || LogSetting == "1")
                    return;

                StackFrame fr = new StackFrame(1, true);

                LogEntry log = new LogEntry();
                log.Categories.Add("General");
                log.Priority = m_priorityInfo;
                log.EventId = C_INT_MSG_ID;
                log.Severity = TraceEventType.Information;
                log.ExtendedProperties.Add("UserLogUTCode", GetUserLogUTCode() + " | ");
                log.Message = string.Format("Entering Method: {0} Info ---> {1}", fr.GetMethod().Name, string.Join(" | ", infos));

                Logger.Write(log);
            }
            catch
            {
            }
        }

        public static void WriteInfo(Dictionary<string, string> dicParams)
        {
            try
            {
                if (LogSetting == "0" || LogSetting == "1")
                    return;

                StackFrame fr = new StackFrame(1, true);
                string strMessage = string.Empty;

                LogEntry log = new LogEntry();
                log.Categories.Add("General");
                log.Priority = m_priorityInfo;
                log.EventId = C_INT_MSG_ID;
                log.Severity = TraceEventType.Information;

                log.ExtendedProperties.Add("UserLogUTCode", GetUserLogUTCode() + " | ");
                strMessage = "Entering Method: " + fr.GetMethod().Name + " Info ---> ";

                foreach (KeyValuePair<string, string> iKeyVal in dicParams)
                {
                    if (iKeyVal.Value == null)
                    {
                        strMessage += iKeyVal.Key + " - NULL | ";
                        log.ExtendedProperties.Add(iKeyVal.Key, "NULL | ");
                    }
                    else
                    {
                        strMessage += iKeyVal.Key + " - " + iKeyVal.Value + " | ";
                        log.ExtendedProperties.Add(iKeyVal.Key, iKeyVal.Value + " | ");
                    }
                }
                log.Message = strMessage;
                Logger.Write(log);
            }
            catch
            {
            }
        }

        //warning message
        public static void WriteWarning(Exception p_objException)
        {
            try
            {
                Logger.Write(p_objException.Message, C_STR_EVENT_CATEGORY, m_priorityWarning, C_INT_MSG_ID,
                             TraceEventType.Warning);
            }
            catch
            {
            }
        }

        public static void WriteWarning(SqlException p_objSqlException)
        {
            try
            {
                Logger.Write(p_objSqlException.Message, C_STR_EVENT_CATEGORY, m_priorityWarning, C_INT_MSG_ID,
                             TraceEventType.Warning);
            }
            catch
            {
            }
        }

        public static void WriteWarning(string p_strMessage)
        {
            try
            {
                Logger.Write(p_strMessage, C_STR_EVENT_CATEGORY, m_priorityWarning, C_INT_MSG_ID, TraceEventType.Warning);
            }
            catch
            {
            }
        }

        //Get Current Context ASPX Page and ascx Control 
        public static string GetCurrentContextForLogging(string CurrentControlName)
        {
            string strPageURL = "";
            string strMessage = "";

            try
            {
                if (CurrentControlName != null && CurrentControlName.Length > 0 && HttpContext.Current != null &&
                    HttpContext.Current.Request != null && HttpContext.Current.Request.Path != null)
                {
                    strPageURL = HttpContext.Current.Request.Path;
                    if (strPageURL.Length > 0)
                    {
                        strPageURL = strPageURL.Substring(strPageURL.LastIndexOf('/') + 1);
                        string strControlURL = CurrentControlName.Substring(CurrentControlName.LastIndexOf('\\') + 1);
                        strMessage = "@ " + strPageURL + " " + strControlURL + " ";
                    }
                }
            }
            catch
            {
            }

            return strMessage;
        }

        //Get Current user's UTCode from Session
        public static string GetUserLogUTCode()
        {
            try
            {
                if (UserLogUTCode == string.Empty && HttpContext.Current != null)
                {
                    for (int i = 0; i < HttpContext.Current.Session.Count; i++)
                    {
                        try
                        {
                            Hashtable attributes = (Hashtable)HttpContext.Current.Session[i];
                            UserLogUTCode = (attributes.ContainsKey("UTCode"))
                                                ? attributes["UTCode"].ToString()
                                                : string.Empty;
                            UserLogUTCode = (UserLogUTCode == string.Empty && attributes.ContainsKey("BPMUTCode"))
                                                ? attributes["BPMUTCode"].ToString()
                                                : string.Empty;
                            if (UserLogUTCode != string.Empty) break;
                        }
                        catch
                        {
                        }
                    }
                }
                else
                    UserLogUTCode = "SYSTEM";
            }
            catch
            {
            }

            return UserLogUTCode;
        }

        //error message
        public static void WriteError(Exception p_objException)
        {
            try
            {
                if (p_objException != null)
                {
                    StackFrame fr = new StackFrame(1, true);
                    StackTrace st = new StackTrace(fr);

                    LogEntry log = new LogEntry();
                    log.Message = GetCurrentContextForLogging(fr.GetFileName()) + " " + p_objException.Message;
                    log.Categories.Add("General");
                    log.Priority = m_priorityError;
                    log.EventId = C_INT_MSG_ID;
                    log.Severity = TraceEventType.Error;

                    log.ExtendedProperties.Add("Method", fr.GetMethod().Name + " | ");
                    log.ExtendedProperties.Add("UserLogUTCode", GetUserLogUTCode() + " | ");
                    log.ExtendedProperties.Add("StackTrace", p_objException.StackTrace);

                    Logger.Write(log);
                }
            }
            catch
            {
            }

            //Logger.Write(p_objException.Message, C_STR_EVENT_CATEGORY, m_priorityError, C_INT_MSG_ID, TraceEventType.Error);
        }

        public static void WriteError(string strURL, Exception p_objException)
        {
            try
            {
                if (p_objException != null)
                {
                    StackFrame fr = new StackFrame(1, true);
                    StackTrace st = new StackTrace(fr);

                    LogEntry log = new LogEntry();
                    log.Message = strURL + p_objException.Message + p_objException.StackTrace;
                    log.Categories.Add("General");
                    log.Priority = m_priorityError;
                    log.EventId = C_INT_MSG_ID;
                    log.Severity = TraceEventType.Error;

                    log.ExtendedProperties.Add("Method", fr.GetMethod().Name + " | ");
                    log.ExtendedProperties.Add("UserLogUTCode", GetUserLogUTCode() + " | ");

                    Logger.Write(log);
                }
            }
            catch
            {
            }

            //Logger.Write(p_objException.Message, C_STR_EVENT_CATEGORY, m_priorityError, C_INT_MSG_ID, TraceEventType.Error);
        }

        public static void WriteError(SqlException p_objSqlException)
        {
            try
            {
                if (p_objSqlException != null)
                {
                    StackFrame fr = new StackFrame(1, true);
                    StackTrace st = new StackTrace(fr);

                    LogEntry log = new LogEntry();
                    log.Message = GetCurrentContextForLogging(fr.GetFileName()) + " " + p_objSqlException.Message;
                    log.Categories.Add("General");
                    log.Priority = m_priorityError;
                    log.EventId = C_INT_MSG_ID;
                    log.Severity = TraceEventType.Error;

                    log.ExtendedProperties.Add("Method", fr.GetMethod().Name + " | ");
                    log.ExtendedProperties.Add("UserLogUTCode", GetUserLogUTCode() + " | ");
                    log.ExtendedProperties.Add("StackTrace", p_objSqlException.StackTrace);
                    Logger.Write(log);
                }
            }
            catch
            {
            }
            //Logger.Write(p_objSqlException.Message, C_STR_EVENT_CATEGORY, m_priorityError, C_INT_MSG_ID, TraceEventType.Error);
        }

        public static void WriteError(string p_strMessage)
        {
            try
            {
                Logger.Write(p_strMessage, C_STR_EVENT_CATEGORY, m_priorityError, C_INT_MSG_ID, TraceEventType.Error);
            }
            catch
            {
            }
        }


        //Write PHIDIAS Events into flat file
        public static void WritePHIDIASEvents(string p_strMessage)
        {
            try
            {
                Logger.Write(p_strMessage, C_STR_EVENT_CATEGORY_PHIDIAS);
            }
            catch
            {
            }
        }

        //Write PHIDIAS Events into flat file based on the level
        public static void WritePHIDIASEvents(string p_strMessage, int Level)
        {
            if (LogSetting == "0" || LogSetting == null)
                return;
            else if (LogSetting == "1" && Level == 1)
            {
                Logger.Write(p_strMessage, C_STR_EVENT_CATEGORY_PHIDIAS);
                return;
            }
            else if (LogSetting == "2")
            {
                Logger.Write(p_strMessage, C_STR_EVENT_CATEGORY_PHIDIAS);
                return;
            }
        }

        #region WriteMethodEntering

        /// <summary>
        /// Log the current entering method param values in MethodEntering category, to the trace listeners in the Listeners collection, if a condition is true.
        /// </summary>
        /// <param name="p_strInputParamValues">The current entering method param values.</param>
        /// <returns>true if message is written successfully; otherwise, false.</returns>
        /// <remarks>
        /// <p>
        /// The category parameter can be used for grouping output messages.
        /// </p>
        /// <p>
        /// This method calls the Write method of the trace listener.
        /// </p>
        /// <p>
        /// By default, the output is written to an instance of DefaultTraceListener.
        /// </p>
        /// </remarks>
        public static bool WriteMethodEntering(params object[] p_strInputParamValues)
        {
            return WriteMethodEntering((new StackFrame(1)).GetMethod(), p_strInputParamValues);
        }

        /// <summary>
        /// Log the specified entering method and param values in MethodEntering category, to the trace listeners in the Listeners collection, if a condition is true.
        /// </summary>
        /// <param name="p_objMethod">The entering method to log.</param>
        /// <param name="p_strInputParamValues">The method param values.</param>
        /// <returns>true if message is written successfully; false otherwise.</returns>
        /// <remarks>
        /// <p>
        /// The category parameter can be used for grouping output messages.
        /// </p>
        /// <p>
        /// This method calls the Write method of the trace listener.
        /// </p>
        /// <p>
        /// By default, the output is written to an instance of DefaultTraceListener.
        /// </p>
        /// </remarks>
        public static bool WriteMethodEntering(MethodBase p_objMethod, params object[] p_strInputParamValues)
        {
            // Be very careful by putting a Try/Catch around the entire routine.
            // We should never throw an exception while logging.
            try
            {
                Logger.Write("Entering method: " + p_objMethod + p_strInputParamValues, C_STR_EVENT_CATEGORY,
                             m_priorityInfo, C_INT_MSG_ID, TraceEventType.Information);

                return true;
            }
            catch //Ignore any exceptions.
            {
                return false;
            }
        }

        #endregion

        #region WriteMethodExiting

        /// <summary>
        /// Log the current Exiting method in MethodExiting category, to the trace listeners in the Listeners collection, if a condition is true.
        /// </summary>
        /// <returns>true if message is written successfully; false otherwise</returns>
        /// <remarks>
        /// <p>
        /// The category parameter can be used for grouping output messages.
        /// </p>
        /// <p>
        /// This method calls the Write method of the trace listener.
        /// </p>
        /// <p>
        /// By default, the output is written to an instance of DefaultTraceListener.
        /// </p>
        /// </remarks>
        public static bool WriteMethodExiting()
        {
            return WriteMethodExiting((new StackFrame(1)).GetMethod());
        }

        public static bool WriteServiceMethodExiting()
        {
            // Be very careful by putting a Try/Catch around the entire routine.
            // We should never throw an exception while logging.
            try
            {
                // Write the exit function message.

                MethodBase p_objMethod = (new StackFrame(1)).GetMethod();
                if (p_objMethod != null)
                {
                    LogEntry log = new LogEntry();
                    log.Message = "Exiting Method: " + p_objMethod.Name;
                    log.Categories.Add("General");
                    log.Priority = m_priorityInfo;
                    log.EventId = C_INT_MSG_ID;
                    log.Severity = TraceEventType.Information;

                    log.ExtendedProperties.Add("Method", p_objMethod.Name + " | ");

                    Logger.Write(log);
                }

                //if (p_objOutputValue != null)
                //    Logger.Write("Exiting method: " + p_objMethod.ToString() + p_objOutputValue.ToString(), C_STR_EVENT_CATEGORY, m_priorityInfo, C_INT_MSG_ID, TraceEventType.Information);	
                //else
                //    Logger.Write("Exiting method: " + p_objMethod.ToString() + " null ", C_STR_EVENT_CATEGORY, m_priorityInfo, C_INT_MSG_ID, TraceEventType.Information);
                return true;
            }
            catch //Ignore any exceptions.
            {
                return false;
            }
        }


        /// <summary>
        /// Log the specified Exiting method in MethodExiting category, to the trace listeners in the Listeners collection, if a condition is true.
        /// </summary>
        /// <param name="p_objMethod">The exiting method to log.</param>
        /// <returns>true if message is writed successfully; otherwise, false.</returns>
        /// <remarks>
        /// <p>
        /// The category parameter can be used to group output messages.
        /// </p>
        /// <p>
        /// This method calls the Write method of the trace listener.
        /// </p>
        /// <p>
        /// By default, the output is written to an instance of DefaultTraceListener.
        /// </p>
        /// </remarks>
        public static bool WriteMethodExiting(MethodBase p_objMethod)
        {
            return WriteMethodExiting(p_objMethod, null);
        }

        /// <summary>
        /// Log the current Exiting method and output values in MethodExiting category, to the trace listeners in the Listeners collection, if a condition is true.
        /// </summary>
        /// <param name="p_objOutputValue">The current method output value.</param>
        /// <returns>true if message is writed successfully; otherwise, false.</returns>
        /// <remarks>
        /// <p>
        /// The category parameter can be used to group output messages.
        /// </p>
        /// <p>
        /// This method calls the Write method of the trace listener.
        /// </p>
        /// <p>
        /// By default, the output is written to an instance of DefaultTraceListener.
        /// </p>
        /// </remarks>
        public static bool WriteMethodExiting(object p_objOutputValue)
        {
            return WriteMethodExiting((new StackFrame(1)).GetMethod(), p_objOutputValue);
        }

        /// <summary>
        /// Log the specified Exiting method and output values in MethodExiting category, to the trace listeners in the Listeners collection, if a condition is true.
        /// </summary>
        /// <param name="p_objMethod">The exiting method to log.</param>
        /// <param name="p_objOutputValue">The method output value.</param>
        /// <returns>true if message is writed successfully; otherwise, false.</returns>
        /// <remarks>
        /// <p>
        /// The category parameter can be used to group output messages.
        /// </p>
        /// <p>
        /// This method calls the Write method of the trace listener.
        /// </p>
        /// <p>
        /// By default, the output is written to an instance of DefaultTraceListener.
        /// </p>
        /// </remarks>
        public static bool WriteMethodExiting(MethodBase p_objMethod, object p_objOutputValue)
        {
            // Be very careful by putting a Try/Catch around the entire routine.
            // We should never throw an exception while logging.
            try
            {
                if (LogSetting == "0" || LogSetting == "1")
                    return false;

                // Write the exit function message.
                if (p_objMethod != null)
                {
                    LogEntry log = new LogEntry();
                    log.Message = "Exiting Method: " + p_objMethod.Name;
                    log.Categories.Add("General");
                    log.Priority = m_priorityInfo;
                    log.EventId = C_INT_MSG_ID;
                    log.Severity = TraceEventType.Information;

                    log.ExtendedProperties.Add("Method", p_objMethod.Name + " | ");
                    log.ExtendedProperties.Add("UserLogUTCode", GetUserLogUTCode() + " | ");

                    Logger.Write(log);
                }

                //if (p_objOutputValue != null)
                //    Logger.Write("Exiting method: " + p_objMethod.ToString() + p_objOutputValue.ToString(), C_STR_EVENT_CATEGORY, m_priorityInfo, C_INT_MSG_ID, TraceEventType.Information);	
                //else
                //    Logger.Write("Exiting method: " + p_objMethod.ToString() + " null ", C_STR_EVENT_CATEGORY, m_priorityInfo, C_INT_MSG_ID, TraceEventType.Information);
                return true;
            }
            catch //Ignore any exceptions.
            {
                return false;
            }
        }

        #endregion

        #region WriteDbCommand
        private static void WriteSql(IDbCommand p_dbCommand, string p_message, Exception p_objException, TraceEventType p_type)
        {
            if ((p_type == TraceEventType.Verbose || p_type == TraceEventType.Information) && (LogSetting == "0" || LogSetting == "1"))
                return;

            string message = "Default message for Sql logging";
            LogEntry log = new LogEntry();

            if (p_dbCommand != null)
            {
                StringBuilder parameters = new StringBuilder();
                try
                {
                    foreach (IDataParameter parameter in p_dbCommand.Parameters)
                    {
                        parameters.Append(parameter.ParameterName).Append("=").Append(parameter.Value).Append(",");
                    }

                    if (!string.IsNullOrEmpty(p_message))
                    {
                        message = p_message + " while executing Sql " + p_dbCommand.CommandText;
                    }
                    else
                    {
                        message = p_dbCommand.CommandText + " executed";
                    }
                    log.Categories.Add("General");
                    log.Priority = m_priorityInfo;
                    log.EventId = C_INT_MSG_ID;
                    log.Severity = p_type;

                    log.ExtendedProperties.Add("SqlDatabase", p_dbCommand.Connection.Database);
                    log.ExtendedProperties.Add("SqlCommand", p_dbCommand.CommandText);
                    log.ExtendedProperties.Add("SqlCommandType", p_dbCommand.CommandType);
                    log.ExtendedProperties.Add("SqlParameters", parameters);
                    log.ExtendedProperties.Add("SqlConnectionTimeout", p_dbCommand.CommandTimeout);
                }
                catch (Exception ex)
                {
                    WriteWarning(ex);
                }

                if (p_objException != null)
                {
                    StackFrame fr = new StackFrame(1, true);
                    StackTrace st = new StackTrace(fr);

                    message = GetCurrentContextForLogging(fr.GetFileName()) + " " + p_objException.Message + " - " + message;
                    log.Categories.Add("General");
                    log.Priority = m_priorityError;
                    log.EventId = C_INT_MSG_ID;
                    log.Severity = TraceEventType.Error;

                    log.ExtendedProperties.Add("Method", fr.GetMethod().Name + " | ");
                    log.ExtendedProperties.Add("UserLogUTCode", GetUserLogUTCode() + " | ");
                    log.ExtendedProperties.Add("StackTrace", p_objException.StackTrace);
                }

                log.Message = message;
                Logger.Write(log);
            }
        }

        public static void WriteSqlDebug(IDbCommand dbCommand)
        {
            WriteSql(dbCommand, null, null, TraceEventType.Verbose);
        }

        public static void WriteSqlInfo(IDbCommand dbCommand, string message)
        {
            WriteSql(dbCommand, message, null, TraceEventType.Verbose);
        }

        public static void WriteSqlWarning(IDbCommand dbCommand, string message)
        {
            WriteSql(dbCommand, message, null, TraceEventType.Verbose);
        }

        public static void WriteSqlError(IDbCommand dbCommand, Exception ex)
        {
            WriteSql(dbCommand, null, ex, TraceEventType.Error);
        }
        #endregion

        #endregion

        public static string BuildLog(object obj)
        {
            StringBuilder sb = new StringBuilder();

            if (obj != null)
                foreach (PropertyInfo pi in obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.GetField | BindingFlags.FlattenHierarchy))
                    sb.AppendFormat("{0} = {1},", pi.Name, pi.GetValue(obj, null));

            return sb.ToString();
        }
    }
}